#include "Lighter.h"
#include "World.h"
#include "Drawer.h"
#include "simplexNoise.h"

#include <cmath>

//test
#include <windows.h>




namespace HW2
{


	Color HW2::shadeOfGrey(int k)
	{
		if(k < 0) k = -k;
		k = k % 255;
		return Color(k,k,k);
	}



	Lighter::Lighter():currentPolygon(ambientLight){
		sPtr = 0;
		//setAmbient(255,255,255);
		isSet = false;
		setAmbient(50,50,50);
		textureIsSet = true;
		currentPolygon.serialNum = -1;
		fogActivated = false;

		pixelSize = 1;
		//type = LIGHT_TYPE_DIRECTIONAL;
		//type = LIGHT_TYPE_POINT;
		//sources[0].type = LIGHT_TYPE_POINT;
		sources[0].type = LIGHT_TYPE_DIRECTIONAL;
		shadingType = FLAT;
		//shadingType = GUARDED;
		//shadingType = PHONG;
		viewVector.X()=0;	
		viewVector.Y()=0;
		viewVector.Z()=1;
		shadows = false;
		//-----initialize shadow---------
		/*if (sources[0].ShadowPointsVecX == NULL){
			sources[0].ShadowPointsVecX = new short[100000000];
			sources[0].ShadowPointsVecY = new short[100000000];
			sources[0].ShadowPointsVecZ = new short[100000000];
		}


		for(int i = 0 ; i< 100000000;i++){
			sources[0].ShadowPointsVecX[i] = 32000;
			sources[0].ShadowPointsVecY[i] = 32000;
			sources[0].ShadowPointsVecZ[i] = 32000;
		}*/
		
		//-------------------------------

		objectNames.clear();
		objectShading.clear();

		k_ambient = 0.2;
		k_specular = 0.5;
		k_diffusive = 0.5;
		n_shininess = 32;
		sources[0].isInViewMode = true;
		sources[0].setColor(255,255,255);
		sources[0].setPosition(400,0,0);
		sources[0].setDirection(1,2,3);
		sources[0].enabled = true;
		baseActivated = false;

		objectNames.clear();
		objectShading.clear();

		fogColor = HW2::Color::Color(255,255,255);
		/*sources[0].setColor(255,255,255);
		sources[0].setPosition(0,0,0);
		sources[0].setDirection(0,0,0);
		sources[0].enabled = true;*/

		for (int i = 1 ; i<8;i++){
			sources[i].isInViewMode = true;
			sources[i].setColor(255,255,255);
			sources[i].setDirection(0,0,0);
			sources[i].setPosition(0,0,0);
			sources[i].enabled = false;
			sources[i].type = LIGHT_TYPE_DIRECTIONAL;
			
		}
		transformLightSources();
	}


	void Lighter::restart(){
		sPtr = 0;
		isSet = true;
		//setAmbient(255,255,255);
		setAmbient(50,50,50);
		currentPolygon.serialNum = -1;
		textureIsSet = false;
		fogActivated = false;
		//type = LIGHT_TYPE_DIRECTIONAL;
		//type = LIGHT_TYPE_POINT;
		sources[0].type = LIGHT_TYPE_POINT;
		//sources[0].type = LIGHT_TYPE_DIRECTIONAL;
		//shadingType = FLAT;
		//shadingType = GUARDED;
		shadingType = PHONG;
		viewVector.X()=0;	
		viewVector.Y()=0;
		viewVector.Z()=1;

		objectNames.clear();
		objectShading.clear();
		objectShadingNames.clear();

		

		shadows = false;
		k_ambient = 0.2;
		k_specular = 0.5;
		k_diffusive = 0.5;
		n_shininess = 32;
		sources[0].isInViewMode = true;
		sources[0].setColor(255,255,255);
		sources[0].setPosition(400,-400,-400);
		sources[0].setDirection(1,2,3);
		sources[0].enabled = true;
		baseActivated = false;

		objectNames.clear();
		objectShading.clear();
		
		fogColor = HW2::Color::Color(255,255,255);
		

		//-----initialize shadow---------
		/*if (sources[0].ShadowPointsVecX == NULL){
			sources[0].ShadowPointsVecX = new short[100000000];
			sources[0].ShadowPointsVecY = new short[100000000];
			sources[0].ShadowPointsVecZ = new short[100000000];
		}
		for(int i = 0 ; i< 100000000;i++){
			sources[0].ShadowPointsVecX[i] = 32000;
			sources[0].ShadowPointsVecY[i] = 32000;
			sources[0].ShadowPointsVecZ[i] = 32000;
		}*/
		
		
		/*if (sources[0].ShadowPointsVec == NULL)
		 sources[0].ShadowPointsVec = new Coordinates[10000000];*/
		//-------------------------------

		for (int i = 1 ; i<8;i++){
			sources[i].isInViewMode = true;
			sources[i].setColor(255,255,255);
			sources[i].setDirection(0,0,0);
			sources[i].setPosition(0,0,0);
			sources[i].enabled = false;
			sources[i].type = LIGHT_TYPE_DIRECTIONAL;
			
		}

		transformLightSources();

	}

	void Lighter::setAmbient(double r  ,double g , double b){

		Color c(r,g,b);

		ambientLight = c;

	}

	void Lighter::setViewVector(double x ,double y,double z){

		viewVector.X() = x;
		viewVector.Y() = y;
		viewVector.Z() = z;


	}

	Coordinates Lighter::pointToCamera(Coordinates c){
		return (viewVector.mult(2000) - c);
	

	}

	Color Lighter::getLightning(Coordinates &c ,Coordinates& origC)
	{

		
			int i =0;

			Color tmpRet;
			if (shadingType == FLAT){
				tmpRet=(currentPolygon.color + (ambientLight*currentPolygon.k)*k_ambient);
				tmpRet.normalizColor();
			}else if(shadingType == GUARDED){

				tmpRet=(interpulateColor(c) + (ambientLight*currentPolygon.k)*k_ambient);
				//tmpRet = interpulateColor(c);
				tmpRet.normalizColor();

			}else if(shadingType == PHONG){
			//tmpRet=(normalIntrpulateColor(c) + (ambientLight*currentPolygon.k)*k_ambient);

					tmpRet=(normalIntrpulateColor(c,origC) + (ambientLight*currentPolygon.k)*k_ambient);
				
				//	tmpRet=(normalIntrpulateColorOriginal(c) + (ambientLight*currentPolygon.k)*k_ambient);
				//tmpRet = interpulateColor(c);
				tmpRet.normalizColor();
			}else if(shadingType == TEXTURE_WOOD){
			

				tmpRet=(normalIntrpulateColor(c,origC) + (ambientLight*currentPolygon.k)*k_ambient);
				tmpRet.normalizColor();
			}else if(shadingType == TEXTURE_MARBEL){
			
				tmpRet=(normalIntrpulateColor(c,origC) + (ambientLight*currentPolygon.k)*k_ambient);				
				tmpRet.normalizColor();
			}else if(shadingType == TEXTURE_RUST){
			
				tmpRet=(normalIntrpulateColor(c,origC) + (ambientLight*currentPolygon.k)*k_ambient);				
				tmpRet.normalizColor();
			}else if(shadingType == TEXTURE_ARMY){
			
				tmpRet=(normalIntrpulateColor(c,origC) + (ambientLight)*k_ambient);				
				tmpRet.normalizColor();
			

			}else if(shadingType == TEXTURE_EARTH){
			
				tmpRet=(normalIntrpulateColor(c,origC) + (ambientLight)*k_ambient);				
				tmpRet.normalizColor();
			}else if(shadingType == TEXTURE_REPTILE_SKIN){
			
				tmpRet=(normalIntrpulateColor(c,origC) + (ambientLight)*k_ambient);				
				tmpRet.normalizColor();
			}else if(shadingType == TEXTURE_MIRROR){
			
				tmpRet=(normalIntrpulateColor(c,origC) + (ambientLight)*k_ambient);				
				tmpRet.normalizColor();
			}
			
			 
			return tmpRet;

	//	}



	}




	Color Lighter::ambient(Coordinates &c){

		if (type == LIGHT_TYPE_DIRECTIONAL){
			return ambientLight*currentPolygon.k;				
		}

	}


	void Lighter::copyPolygon(Polygon& p){
		HW2::Drawer &d = HW2::Drawer::get();
		currentPolygon.color = 0;

		//currentPolygon.coordinatesColor.empty();


		currentPolygon.k = p.k;

		currentPolygon.coordinates = p.coordinates;
		currentPolygon.normal = p.normal;
		currentPolygon.normals = p.normals;
		currentPolygon.serialNum = p.serialNum;
		currentPolygon.coordinatesColor = p.coordinatesColor;
		

		for(int i = 0; i< objectNames.size(); i++){

			if(objectNames[i].compare(p.name)==0){
				shadingType = objectShading[i];

			}

		}

		for(unsigned int i = 0; i< currentPolygon.coordinates.size();i++){
			currentPolygon.coordinates[i] = d.transform(currentPolygon.coordinates[i]);
		}
		//currentPolygon.coordinatesColor.empty();
		for(unsigned int i = 0; i< currentPolygon.normals.size();i++){
			currentPolygon.normals[i].unitVector = d.transform(currentPolygon.normals[i].unitVector);
			currentPolygon.coordinatesColor.push_back(0);
			
			currentPolygon.normals[i].unitVector.makeUnitVec();
		}
		currentPolygon.normal.unitVector = d.transform(currentPolygon.normal.unitVector);
		currentPolygon.normal.unitVector.makeUnitVec();
       

		for(int i = 0 ; i < 8 ;i++){


			if (sources[i].type == LIGHT_TYPE_POINT){
				calcPointLight(i);
			
			}else if (sources[i].type == LIGHT_TYPE_DIRECTIONAL){

				calcDirectLight(i);

			}
		}


		/*for(int i = 0 ; i < 8 ;i++){
			if (sources[i].enabled == true){			
				double ct = cosTeta(currentPolygon.normal.unitVector,sources[i].direction);
				double alpha = cosAlpha( currentPolygon.normal.unitVector,sources[i].direction,ct);
				if (ct < 0) 
					ct = 0;
				if (alpha < 0)
					alpha = 0;
				currentPolygon.color = currentPolygon.color + sources[i].color*((currentPolygon.k)*ct + (currentPolygon.ks)*pow(alpha,2)) ;
				//currentPolygon.color = currentPolygon.color + sources[i].color*((currentPolygon.k)*ct ) ;
				for (unsigned int j = 0; j < currentPolygon.normals.size();j++){
					double ct =cosTeta(currentPolygon.normals[j].unitVector,sources[i].direction);
					if (ct < 0)
						ct = 0;
					currentPolygon.coordinatesColor[j] = currentPolygon.coordinatesColor[j] + (currentPolygon.k*sources[i].color)*ct;

				}

			}
		}*/






	}


	void Lighter::transformLightSources(){
		for (unsigned int i = 0; i<8 ;i++){
			/*if(sources[i].enabled){
				if (!sources[i].isInViewMode){
					//sources[i].transformLightSources();
					sources[i].setViewMode(LIGHT_SPACE_LOCAL);
				}else{

					sources[i].setViewMode(LIGHT_SPACE_VIEW);

				}

			}*/
			

		}


	}

	void Lighter::calcDirectLight(int i){
		
		
		Color specColor(0,0,0); 
			if (sources[i].enabled == true){			
				double ct = cosTeta(currentPolygon.normal.unitVector,sources[i].direction);
				
				if (ct < 0) 
					ct = 0;
				double alpha = cosAlpha( currentPolygon.normal.unitVector,sources[i].direction,ct,pointToCamera(currentPolygon.center()));
				if (alpha < 0)
					alpha = 0;
				
				
			
					currentPolygon.color = currentPolygon.color + sources[i].color*(currentPolygon.k)*(ct*k_diffusive) + sources[i].color*pow(alpha,n_shininess)*(k_specular) ;
				for ( int j = 0; j < currentPolygon.normals.size();j++){
					double ct =cosTeta(currentPolygon.normals[j].unitVector,sources[i].direction);
					if (ct < 0)
						ct = 0;
					
					currentPolygon.coordinatesColor[j] = currentPolygon.coordinatesColor[j] + (currentPolygon.k*sources[i].color)*(ct*k_diffusive);
					

				}

			}
		

	}


	void Lighter::calcPointLight(int i){

		
			if (sources[i].enabled == true){	
		
				
				double ct = cosTeta(currentPolygon.normal.unitVector,sources[i].getDirectionFromPoint(currentPolygon.center()));
				
				if (ct < 0) 
					ct = 0;

				double alpha = cosAlpha( currentPolygon.normal.unitVector,sources[i].getDirectionFromPoint(currentPolygon.center()),ct,pointToCamera(currentPolygon.center()));
				if (alpha < 0)
					alpha = 0;
				currentPolygon.color = currentPolygon.color + sources[i].color*(currentPolygon.k)*(ct*k_diffusive) + sources[i].color*pow(alpha,n_shininess)*(k_specular) ;
			
				for (unsigned int j = 0; j < currentPolygon.normals.size();j++){
					
					double ct =cosTeta(currentPolygon.normals[j].unitVector,sources[i].getDirectionFromPoint(currentPolygon.coordinates[j]));
					
					if (ct < 0)
						ct = 0;
					
					currentPolygon.coordinatesColor[j] = currentPolygon.coordinatesColor[j] + (currentPolygon.k*sources[i].color)*ct;
					
				}

			}
		
	}


	double Lighter::cosTeta(Coordinates& p1, Coordinates& p2){
		/*p2 *=(-1);
		double p1Norm = sqrt(p1.X()*p1.X() + p1.Y()*p1.Y() + p1.Z()*p1.Z());
		double p2Norm = sqrt(p2.X()*p2.X() + p2.Y()*p2.Y() + p2.Z()*p2.Z());
		double dot = p1.X()*p2.X() + p1.Y()*p2.Y() + p1.Z()*p2.Z();
		if (p1Norm*p2Norm == 0){
			return 0;
		}
		double ans = (dot/(p1Norm*p2Norm));
		return ans;*/
		double p1Norm = sqrt(p1.X()*p1.X() + p1.Y()*p1.Y() + p1.Z()*p1.Z());
		double p2Norm = sqrt(p2.X()*p2.X() + p2.Y()*p2.Y() + p2.Z()*p2.Z());
		//double dot = p1.X()*(-p2.X()) + p1.Y()*(-p2.Y()) + p1.Z()*(-p2.Z());
		if (p1Norm*p2Norm == 0){
			return 0;
		}
		double ans = (( p1.X()*(-p2.X()) + p1.Y()*(-p2.Y()) + p1.Z()*(-p2.Z()))/(p1Norm*p2Norm));
		return ans;

	}


	Color Lighter::interpulateColor(Coordinates& c){
		
		
		
		int tresh(5);
		

	
		Coordinates p1 = currentPolygon.coordinates[0];
		Coordinates f1 = p1 - c;
		p1.normalize();
		
		for (int i = 2 ; i < currentPolygon.coordinates.size();i++){
		Coordinates p2	 =  currentPolygon.coordinates[i-1];
		Coordinates p3	 =  currentPolygon.coordinates[i];
		
		Coordinates f2	 =  p2 - c;
		Coordinates f3	 =  p3 - c ;
		
		
		
		Coordinates va = (p1 -p2).cross(p1-p3);
		Coordinates va1 = f2.cross(f3);
		Coordinates va2 = f3.cross(f1);
		Coordinates va3 = f1.cross(f2);
		float a = va.norm();
		float a1 = ((va1.norm())/a)*sign(va.dot(va1));
		float a2 = ((va2.norm())/a)*sign(va.dot(va2));
		float a3 = ((va3.norm())/a)*sign(va.dot(va3));


		//if (((a1 + a2 +a3) > 0.90) && ((a1 + a2 +a3) < 1.10)){
		if((a1>= -0.001) && (a2 >= -0.001) && (a3>=-0.001)&&(a1<= 1.001) && (a2 <= 1.001) && (a3<=1.001)){
			Color tmpColor = ((currentPolygon.coordinatesColor[0]*(a1)) + (currentPolygon.coordinatesColor[i-1]*(a2)) + (currentPolygon.coordinatesColor[i]*(a3)));
				

			if (fogActivated){
		//Color fogColor(255,255,255);
		double fogVal =600/(sqrt((0-c.X())*(0-c.X())+(0-c.Y())*(0-c.Y())+(-1000-c.Z())*(-1000-c.Z())));
			if (fogVal > 1)
				fogVal = 1;
			fogVal = fogVal*fogVal;	
			Color newtmpColor = tmpColor*(fogVal) + fogColor*(1-fogVal);
			return newtmpColor;
		}

		    	return tmpColor;

			}
		}
		Color def(0,0,255);
		return def;//currentPolygon.color;
}





		
Color Lighter::normalIntrpulateColor(Coordinates& c,Coordinates& cOrig){

	
		/*if (cosTeta(currentPolygon.normal.unitVector,viewVector) < 0)
			return HW2::Color(0,0,0);*/
		
	  
	 // c =currentPolygon.coordinates[1];
		double f1[3];
		double f2[3];
		double f3[3];
		double p1[3];
		double p2[3];
		double p3[3];
		Color tmpColor(0,0,0);
		Coordinates tmpNormal(0,0,0);
		
		
			p1[0] = currentPolygon.coordinates[0].X();
			p1[1] = currentPolygon.coordinates[0].Y();
			p1[2] = currentPolygon.coordinates[0].Z();
		
	
		f1[0] = p1[0] - c.X();
		f1[1] = p1[1] - c.Y();
		f1[2] = p1[2] - c.Z();

		

		for (int i = 2 ; i < currentPolygon.coordinates.size();i++){
		
		Coordinates p2x	 =  currentPolygon.coordinates[i-1];//
		p2[0] = currentPolygon.coordinates[i-1].X();
		p2[1] = currentPolygon.coordinates[i-1].Y();
		p2[2] = currentPolygon.coordinates[i-1].Z();
		Coordinates p3x	 =  currentPolygon.coordinates[i];//
		p3[0] = currentPolygon.coordinates[i].X();
		p3[1] = currentPolygon.coordinates[i].Y();
		p3[2] = currentPolygon.coordinates[i].Z();
		
		
		f2[0] = p2[0] - c.X();
		f2[1] = p2[1] - c.Y();
		f2[2] = p2[2] - c.Z();


	
		f3[0] = p3[0] - c.X();
		f3[1] = p3[1] - c.Y();
		f3[2] = p3[2] - c.Z();
		
		
		

	
		double va[3];
		va[0] = (p1[1] - p2[1])*(p1[2] - p3[2]) - (p1[2] - p2[2])*(p1[1] - p3[1]);
		va[1] = (p1[0] - p2[0])*(p1[2] - p3[2]) - (p1[2] - p2[2])*(p1[0] - p3[0]);
		va[2] = (p1[0] - p2[0])*(p1[1] - p3[1]) - (p1[1] - p2[1])*(p1[0] - p3[0]);
	
	
		
		double va1[3];
		va1[0] = (f2[1])*(f3[2]) - (f2[2])*(f3[1]);
		va1[1] = (f2[0])*(f3[2]) - (f2[2])*(f3[0]);
		va1[2] = (f2[0])*(f3[1]) - (f2[1])*(f3[0]);


		
		double va2[3];
		va2[0] = (f3[1])*(f1[2]) - (f3[2])*(f1[1]);
		va2[1] = (f3[0])*(f1[2]) - (f3[2])*(f1[0]);
		va2[2] = (f3[0])*(f1[1]) - (f3[1])*(f1[0]);

		

		double va3[3];
		va3[0] = (f1[1])*(f2[2]) - (f1[2])*(f2[1]);
		va3[1] = (f1[0])*(f2[2]) - (f1[2])*(f2[0]);
		va3[2] = (f1[0])*(f2[1]) - (f1[1])*(f2[0]);
	
		float a = sqrt(va[0]*va[0] + va[1]*va[1]+va[2]*va[2]);
		
		
		float a1 = ((sqrt(va1[0]*va1[0] + va1[1]*va1[1]+va1[2]*va1[2]))/a)*(((va[0]*va1[0] + va[1]*va1[1] +va[2]*va1[2]) < 0) ? -1 : 1);
		


		
		
		
		float a2 = ((sqrt(va2[0]*va2[0] + va2[1]*va2[1]+va2[2]*va2[2]))/a)* (((va[0]*va2[0] + va[1]*va2[1] +va[2]*va2[2]) < 0) ? -1 : 1);
		

	
		float a3 = ((sqrt(va3[0]*va3[0] + va3[1]*va3[1]+va3[2]*va3[2]))/a)*(((va[0]*va3[0] + va[1]*va3[1] +va[2]*va3[2]) < 0) ? -1 : 1);
//----------------------------

		
		if((a1>= -0.001) && (a2 >= -0.001) && (a3>=-0.001)&&(a1<= 1.001) && (a2 <= 1.001) && (a3<=1.001)){
			 tmpNormal = ((currentPolygon.normals[0].unitVector.mult(a1)) + (currentPolygon.normals[i-1].unitVector.mult(a2)) + (currentPolygon.normals[i].unitVector.mult(a3)));
			 
			}
		
	}
	

		/*float t = turbulence(c,0.01,6);
			tmpNormal.X() + t;
			tmpNormal.Y() + t;
			tmpNormal.Z() + t;

		
		


		t = turbulence(c,0.1,4);
		tmpNormal*= t;
		t = turbulence(c,0.01,0.1) ;*/
		//float t = turbulence(c,0.1,0.5);

		float t = 1;
		float ts = 1;

		if (shadingType == TEXTURE_RUST){
			/*t = scaled_raw_noise_3d(0.3,1.5,cOrig.X()/0.6,cOrig.Y()/0.6,cOrig.Z()/0.6);
			tmpNormal.X() + t;
			tmpNormal.Y() + t;
			tmpNormal.Z() + t;*/
			//ts = turbulence(c,0.01,6);
			
			
			
			if (turbulence(cOrig,0.1,1) < 0.6){
				ts=0.1;
			
			}
			/*t = turbulence(cOrig/0.02,0.1,6) - turbulence(c/2,1,6);
			tmpNormal.X() + t;
			tmpNormal.Y() + t;
			tmpNormal.Z() + t;*/

		}
		else if (shadingType == TEXTURE_ARMY){
			t = turbulence(c,0.1,6);
			ts = t;
			tmpNormal.X() + t;
			tmpNormal.Y() + t;
			tmpNormal.Z() + t;


		}else if(shadingType == TEXTURE_EARTH){
			t = 2;

		}else if(shadingType == TEXTURE_REPTILE_SKIN){
			t = 1.5;
			
			/*double t = (turbulence(c,0.5,6) );
			//ts = x;
			if (t < 0.15 || t > 0.4){
				ts = t;
			tmpNormal.X() + t;
			tmpNormal.Y() + t;
			tmpNormal.Z() + t;
			}*/

			t = turbulence(c,0.1,6);
			ts = t;
			tmpNormal.X() + t;
			tmpNormal.Y() + t;
			tmpNormal.Z() + t;
			
		}
		if (shadows == true){
			if(sources[0].isShadowed(c))
				t=0.1;
				//ts = 0;
		}

		for(int i = 0 ; i < 8 ;i++){

			

			if( sources[i].enabled){
				if (sources[i].type == LIGHT_TYPE_POINT ){
					double ct = cosTeta(tmpNormal,sources[i].getDirectionFromPoint(c));
					if (ct < 0)
						ct = 0;
					double alpha = cosAlpha(tmpNormal,sources[i].getDirectionFromPoint(c),ct,pointToCamera(c));
					if (alpha < 0)
							alpha = 0;
					//tmpColor = tmpColor + (sources[i].color)*(material(cOrig))*(ct*k_diffusive) + (sources[i].color)*pow(alpha,n_shininess)*(k_specular);
					//tmpColor = tmpColor + (sources[i].color)*(material(cOrig))*(ct*k_diffusive*t) + (sources[i].color)*pow(alpha,n_shininess)*(k_specular*ts);
					if(	shadingType == TEXTURE_MIRROR){
					tmpColor = tmpColor + (sources[i].color)*(material(cOrig))*(ct*k_diffusive*1.5) + (sources[i].color)*pow(alpha,5)*(2);
					}else{
						tmpColor = tmpColor + (sources[i].color)*(material(cOrig))*(ct*k_diffusive*t) + (sources[i].color)*pow(alpha,n_shininess)*(k_specular*ts);
					}
				}else if (sources[i].type == LIGHT_TYPE_DIRECTIONAL ){

					double ct = cosTeta(tmpNormal,sources[i].direction);
					if (ct < 0)
						ct = 0;
					double alpha = cosAlpha(tmpNormal,sources[i].direction,ct,pointToCamera(c));
					if (alpha < 0)
							alpha = 0;					
						//tmpColor = tmpColor + (sources[i].color)*(material(cOrig))*(ct*k_diffusive) + (sources[i].color)*pow(alpha,n_shininess)*(k_specular);
					if(	shadingType == TEXTURE_MIRROR){
					tmpColor = tmpColor + (sources[i].color)*(material(cOrig))*(ct*k_diffusive*1.5) + (sources[i].color)*pow(alpha,5)*(2);
					}else{
						tmpColor = tmpColor + (sources[i].color)*(material(cOrig))*(ct*k_diffusive*t) + (sources[i].color)*pow(alpha,n_shininess)*(k_specular*ts);
					}
				}
				
			}
		}

		//--------FOG TEST-----------------------------

	if (fogActivated){
		//Color fogColor(255,255,255);
		double fogVal =600/(sqrt((0-c.X())*(0-c.X())+(0-c.Y())*(0-c.Y())+(-1000-c.Z())*(-1000-c.Z())));
		if (fogVal > 1)
			fogVal = 1;
		fogVal = fogVal*fogVal;	
		Color newtmpColor = tmpColor*(fogVal) + fogColor*(1-fogVal);
		return newtmpColor;
	}
		//----------------------------------------------

		
		return tmpColor;
	}		




	float Lighter::turbulence(const Coordinates& c,float scale,float pixSiz){

		float t = 0;
		//float scale = 0.006;
		while (scale < pixSiz){
			t+= abs(raw_noise_3d(c.data[0]/scale,c.data[1]/scale,c.data[2]/scale)*scale);
			scale*=2;
		}
		return t;

	}

#define SIZE1 3	
	Color Lighter::material(Coordinates c){
		
		
		//marbel
		HW2::World& w = HW2::World::get();
		float Xsize = w.maxPoint.X() - w.minPoint.X();
		float Ysize =  w.maxPoint.Y() - w.minPoint.Y();
		 if (shadingType == PHONG){
			
			return HW2::Color::Color(currentPolygon.k.r,currentPolygon.k.g,currentPolygon.k.b);
		 }

		 if (shadingType == TEXTURE_MIRROR){
			
			//return HW2::Color::Color(currentPolygon.k.r,currentPolygon.k.g,currentPolygon.k.b);
			if(backImage){
				double u = sqrt((atan(c.X()/c.Z())+3.14)/6.38);
				double v = ((-c.Y())+4)/8;
				//u*=u;
				v*=v*v;
				int ww = backImage->wrapper.GetWidth();
				int wh = backImage->wrapper.GetHeight();
			 int col = backImage->wrapper.GetValue(static_cast<int>((u)*ww)%backImage->wrapper.GetWidth(), static_cast<int>((v)*wh) % backImage->wrapper.GetHeight());
			//col/=2;	
			 double r = GET_R(col);
			 double g = GET_G(col);
			 double b = GET_B(col);
			 r/=255;
			 g/=255;
			 b/=255;
			  Color retColor(r,g,b);
			  return retColor;

			}
			return HW2::Color::Color(currentPolygon.k.r,currentPolygon.k.g,currentPolygon.k.b);
			 // int2Color(wrapper.GetValue(x%wrapper.GetWidth(), y % wrapper.GetHeight()));
			
		 }
		 
		 if(shadingType == TEXTURE_REPTILE_SKIN){
			//double x = abs(sin((c.X()*c.X()+c.Y()*c.Y()+c.Z()*c.Z())*10));
			double x = (turbulence(c/0.4,0.5,1) );
			Color tmp(currentPolygon.k.r/2.5 - x/2 ,currentPolygon.k.g/2.5 - x/2,currentPolygon.k.b/2.5 - x/2);
			//double y = (turbulence(c/0.01,0.5,6)/6 );
			//Color dirt(-y/2,-y/2,-y/2);
			if (x > 0.2 && x < 0.5){
				tmp = HW2::Color::Color(currentPolygon.k.r/1.5 - x/2,currentPolygon.k.g/1.5 - x/2,currentPolygon.k.b/1.5 - x/2);
			}

			if (x > 0.1 && x < 0.2){
				tmp = HW2::Color::Color(0,0,0);
			}
			//x = sin((c.Y()	+ turbulence(c/1.5,Xsize/200,(Xsize)))/2) ;
			x = sin((c.Y()	+ turbulence(c/1.5,0.01,2) ));
			x= sqrt(abs(x));		
			Color vains(currentPolygon.k.r*x,currentPolygon.k.g*x,currentPolygon.k.b*x);

		    

			//if (sin(c.X()) > 0)
				return tmp*(x)+vains*(1-x);
			//return tmp ;
		}
		 if (shadingType == TEXTURE_EARTH){
	
			
			double x = turbulence(c,0.2,2) ;
			
			Color tmp(0,0,1);//blue
		
			 x = turbulence(c/1.1,0.01,2) ;
		if (x > 0.8){//good rust
			x = x/7;
			 tmp = HW2::Color::Color(0,1-x,0);

		}

		
			//x = scaled_raw_noise_3d(0, 1, c.X()/3, c.Y(), c.Z() );
		x = (turbulence(c/1.1,0.01,4)/4 );
		
			Color cloudsColor(2,2,2);
			tmp = tmp*(1-x) + cloudsColor*x;
	

		
		

		return tmp;


		 }	
 if (shadingType == TEXTURE_ARMY){
	
		//return HW2::Color::Color(currentPolygon.k.r,currentPolygon.k.g,currentPolygon.k.b);

	 float x = turbulence(c,0.3,2) ;
		Color tmp(0,0,0);//black
		if (x < 0.6)
			 tmp = HW2::Color::Color(0.49,0.43,0.29);//yellow

		x = turbulence(c,0.5,4) ;
		if (x > 0.6 && x < 1.5)
			 tmp = HW2::Color::Color(0.19,0.23,0.09);//green

		x = turbulence(c,0.6,3) ;
		if (x > 0.6 && x < 1.2)
			 tmp = HW2::Color::Color(0.13,0.09,0.03);//brown

	

		
		return tmp;
 }

    if (shadingType == TEXTURE_RUST){
	
	//	return HW2::Color::Color(currentPolygon.k.r,currentPolygon.k.g,currentPolygon.k.b);
		
		float x = turbulence(c,0.1,1) ;
		//Color tmp(currentPolygon.k.r,currentPolygon.k.g,currentPolygon.k.b);
		Color tmp(0,0,0);
		if (x < 0.6){
			x = x/2;
			 tmp = HW2::Color::Color(0.28+x,0.16+x,0.15+x);
		}

		x = turbulence(c,0.5,4) ;
		if (x < 0.4){
			x = x/2;
			// tmp = HW2::Color::Color(0.85+x,0.57+x,0.35+x);
			 tmp = HW2::Color::Color(0.85-x,0.57-x,0.35-x);
		}
		x = turbulence(c,0.2,2) ;
		if (x < 0.8){//good rust
			x = x;
			 tmp = HW2::Color::Color(0.97-x,0.72-x,0.56-x);

		}

		
		

		x = turbulence(c,0.1,1) ;

		if (x > 0.6){//this can work for land
			x = x/10;
			 tmp = HW2::Color::Color(0.69+x,0.35+x,0.17+x);

		}
		x = turbulence(c,0.1,1) ;
		if (x > 0.8 )
			 tmp = HW2::Color::Color(currentPolygon.k.r,currentPolygon.k.g,currentPolygon.k.b);//brown	

		

		return tmp;
	
	
	}	


     if (shadingType == TEXTURE_MARBEL){		
		 	float x = sin((c.X() + turbulence(c,Xsize/200,(Xsize/3)))) ;
			x= sqrt(abs(x));		
			return HW2::Color::Color(x,x,x);
	 }
	 //wood
		if (shadingType == TEXTURE_WOOD){
		//	float x =  (abs(     sin(       ((c.X()*c.X() +c.Z()*c.Z())*3 + turbulence(c,0.1,0.4))*5     )                 ))*0.2;
				//float x =  (abs(     sin(       ((c.X()*c.X() +c.Z()*c.Z())*3 + turbulence(c,0.1,0.2))*10     )                 ))*0.2;
				float x =  (abs(     sin(       ((c.X()*c.X() +c.Z()*c.Z())*(Xsize/2) + turbulence(c,Xsize/60,Xsize/35))*(30/Xsize)     )                 ))*0.2;
			return HW2::Color::Color(0.7 + x,0.5 + x,0.2 + x);
		}	
	}

	int  Lighter::sign(double c){
		if ( c < 0){
			return -1;

		}
		return 1;

	}


	Color Lighter::CalcFog(Coordinates& c){

		return HW2::Color(255,255,255);
	}


	Color Lighter::normalIntrpulateColorOriginal(Coordinates& c){

		

		Color tmpColor(0,0,0);
		Coordinates tmpNormal(0,0,0);

		Coordinates p1 = currentPolygon.coordinates[0];
		Coordinates f1 = p1 - c;
		p1.normalize();
		

		for (int i = 2 ; i < currentPolygon.coordinates.size();i++){
		Coordinates p2	 =  currentPolygon.coordinates[i-1];
		Coordinates p3	 =  currentPolygon.coordinates[i];
		
		Coordinates f2	 =  p2 - c;
		Coordinates f3	 =  p3 - c;
		
		
		
		Coordinates va = (p1 -p2).cross(p1-p3);
		Coordinates va1 = f2.cross(f3);
		Coordinates va2 = f3.cross(f1);
		Coordinates va3 = f1.cross(f2);
		float a = va.norm();
		float a1 = ((va1.norm())/a)*sign(va.dot(va1));
		float a2 = ((va2.norm())/a)*sign(va.dot(va2));
		float a3 = ((va3.norm())/a)*sign(va.dot(va3));



//----------------------------


		if (((a1 + a2 +a3) > 0.90) && ((a1 + a2 +a3) < 1.10)){
			 tmpNormal = ((currentPolygon.normals[0].unitVector.mult(a1)) + (currentPolygon.normals[i-1].unitVector.mult(a2)) + (currentPolygon.normals[i].unitVector.mult(a3)));
		
		    	

			}
		}


		

		for(int i = 0 ; i < 8 ;i++){
			if( sources[i].enabled){
				if (sources[i].type == LIGHT_TYPE_POINT ){
					double ct = cosTeta(tmpNormal,sources[i].getDirectionFromPoint(c));
					if (ct < 0)
						ct = 0;
					double alpha = cosAlpha(tmpNormal,sources[i].getDirectionFromPoint(c),ct,pointToCamera(c));
					if (alpha < 0)
							alpha = 0;

					//tmpColor = tmpColor + (sources[i].color)*((currentPolygon.k)*(ct*k_diffusive) + (currentPolygon.ks)*pow(alpha,n_shininess)*(k_specular));
					//tmpColor = tmpColor + (sources[i].color)*(currentPolygon.k)*(ct*k_diffusive) + (sources[i].color)*pow(alpha,n_shininess)*(k_specular);
					tmpColor = tmpColor + (sources[i].color)*(currentPolygon.k)*(ct*k_diffusive) + (sources[i].color)*pow(alpha,n_shininess)*(k_specular);
				}else if (sources[i].type == LIGHT_TYPE_DIRECTIONAL ){

					double ct = cosTeta(tmpNormal,sources[i].direction);
					if (ct < 0)
						ct = 0;
					double alpha = cosAlpha(tmpNormal,sources[i].direction,ct,pointToCamera(c));
					if (alpha < 0)
							alpha = 0;

					//tmpColor = tmpColor + (sources[i].color)*((currentPolygon.k)*(ct*k_diffusive) + (currentPolygon.ks)*pow(alpha,n_shininess)*(k_specular));
						//tmpColor = tmpColor + (sources[i].color)*(currentPolygon.k)*(ct*k_diffusive) +  (sources[i].color)*pow(alpha,n_shininess)*(k_specular);
					tmpColor = tmpColor + (sources[i].color)*(currentPolygon.k)*(ct*k_diffusive) +  (sources[i].color)*pow(alpha,n_shininess)*(k_specular);
				}
				
			}
		}

		return tmpColor;
	}		

		
		





	Coordinates Lighter::calcReflectionVec(Coordinates& normal, Coordinates& LightVec,double teta)
	{

	/*	teta = acos(teta);
		Coordinates tmpNormal = normal;

		double tmpSize = 2*sin(1.57079 - teta)*(LightVec.norm());
		tmpNormal *= tmpSize;
		tmpNormal = LightVec.add(tmpNormal);
		tmpNormal.makeUnitVec();
		return tmpNormal;*/
	 
		Coordinates tmpNormal = normal;

		tmpNormal *= 2*sin(1.57079 - acos(teta))*(LightVec.norm());;
		tmpNormal = LightVec.add(tmpNormal);
		tmpNormal.makeUnitVec();
		return tmpNormal;
		
	}



	double cosTeta2(Coordinates& p1, Coordinates& p2){
		//p2 *=(-1);
		/*double p1Norm = sqrt(p1.X()*p1.X() + p1.Y()*p1.Y() + p1.Z()*p1.Z());
		double p2Norm = sqrt(p2.X()*p2.X() + p2.Y()*p2.Y() + p2.Z()*p2.Z());
		double dot = p1.X()*p2.X() + p1.Y()*p2.Y() + p1.Z()*p2.Z();
		if (p1Norm*p2Norm == 0){
			return 0;
		}
		double ans = (dot/(p1Norm*p2Norm));
		return ans;*/

		return (p1.X()*p2.X() + p1.Y()*p2.Y() + p1.Z()*p2.Z())/((sqrt(p1.X()*p1.X() + p1.Y()*p1.Y() + p1.Z()*p1.Z()))*(sqrt(p2.X()*p2.X() + p2.Y()*p2.Y() + p2.Z()*p2.Z())));

	}


	double Lighter::cosAlpha(Coordinates& normal, Coordinates& LightVec,double teta,Coordinates c){

	
	/*	if (((LightVec.X()== 0)&&(LightVec.Y()== 0)&&(LightVec.Z()== 0))||((normal.X() == 0)&&(normal.Y() == 0)&&(normal.Z() == 0))||(teta <= 0))
			return 0;
		
		Coordinates refVec = calcReflectionVec(normal,LightVec,teta);
		Coordinates tmpv= viewVector;
		c.makeUnitVec();
		//we inverce the vec here
		return cosTeta(refVec,c);*/
		if (((LightVec.X()== 0)&&(LightVec.Y()== 0)&&(LightVec.Z()== 0))||((normal.X() == 0)&&(normal.Y() == 0)&&(normal.Z() == 0))||(teta <= 0))
			return 0;
		
		
		//Coordinates tmpv= viewVector;
		c.makeUnitVec();
		//we inverce the vec here
		return cosTeta(calcReflectionVec(normal,LightVec,teta),c);
	}


  




	// orig is before transformation
	// c is before projection
	Color getLightedColor(Coordinates c, Coordinates orig, Polygon &p)
	{

		
		//static Lighter l;
		static Lighter &l = Lighter::get();
	
		//if (p.name.compare("Shadow")==0)
			//return HW2::Color(0,0,0);
		
		if (l.shadows == true)
				l.sources[0].addToShadowVec(c);

		

			/*if(l.sources[0].isShadowed(c))
				return HW2::Color(0,0,0);*/

		
		

		if (l.currentPolygon.serialNum != p.serialNum){
			if (l.currentPolygon.serialNum == 1){
				int i = 1;

			}
			l.copyPolygon(p);
		}

		if ((c.X() > 665)&&(c.X() < 674)&&(c.Y() > 260)&&(c.Y() < 270)){
			int i = 7;

		}

		Color tmp = l.getLightning(c,orig);
		
		return tmp;
		
	}








}





